// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// VerilogLexer class implements Lexer interface and is implemented in terms
// of verilogFlexLexer that is generated by Flex.

#ifndef VERIBLE_VERILOG_PARSER_VERILOG_LEXER_H_
#define VERIBLE_VERILOG_PARSER_VERILOG_LEXER_H_

// verilog.lex has "%prefix=verilog", meaning the class flex creates is
// verilogFlexLexer. Unfortunately, FlexLexer.h doesn't have proper ifdefs
// around its inclusion, so we have to put a bar around it here.
#include "verible/common/lexer/flex-lexer-adapter.h"
#include "verible/common/text/token-info.h"

// clang-format off
#ifndef _FLEXLEXER_H_
#  undef yyFlexLexer  // this is how FlexLexer.h says to do things
#  define yyFlexLexer verilogFlexLexer
#  include <FlexLexer.h>
#endif
// clang-format on

#include <functional>

#include "absl/strings/string_view.h"

namespace verilog {

class VerilogLexer : public verible::FlexLexerAdapter<verilogFlexLexer> {
  using parent_lexer_type = verible::FlexLexerAdapter<verilogFlexLexer>;

 public:
  explicit VerilogLexer(absl::string_view code);

  // Restart lexer with new input stream.
  void Restart(absl::string_view) final;

  // Returns true if token is invalid.
  bool TokenIsError(const verible::TokenInfo &) const final;

  // Filter predicate that can be used for testing and parsing.
  static bool KeepSyntaxTreeTokens(const verible::TokenInfo &);

 private:
  // Main lexing function. Will be defined by Flex.
  int yylex() final;

  // These variables are controlled by the lexer code (verilog.lex).

  // for macro call argument lexing
  int balance_ = 0;

  // TODO(fangism): This won't be needed.  Remove when appropriate.
  // for keeping track of end of macro-id
  int macro_id_length_ = 0;

  // In the MACRO_ARG_UNLEXED state  (verilog.lex), track the number of
  // characters excluding trailing spaces/newlines.
  int macro_arg_length_ = 0;
};

// Recursively lex the given 'text', and apply 'func' to each subtoken.
void RecursiveLexText(
    absl::string_view text,
    const std::function<void(const verible::TokenInfo &)> &func);

}  // namespace verilog

#endif  // VERIBLE_VERILOG_PARSER_VERILOG_LEXER_H_
